<!DOCTYPE html>
<html lang="en">
	<head>
		<meta charset="UTF-8" />
		<meta http-equiv="X-UA-Compatible" content="IE=edge" />
		<meta name="viewport" content="width=device-width, initial-scale=1.0" />
		<title>简单实现虚拟列表</title>
	</head>
	<style>
		.list-view {
			height: 400px;
			overflow: auto;
			position: relative;
			border: 1px solid #aaa;
		}

		.list-view-phantom {
			position: absolute;
			left: 0;
			top: 0;
			right: 0;
			z-index: -1;
		}

		.list-view-content {
			left: 0;
			right: 0;
			top: 0;
			position: absolute;
		}

		.list-view-item {
			padding: 5px;
			color: #666;
			line-height: 30px;
			box-sizing: border-box;
		}

		[v-cloak] {
			display: none;
		}
	</style>

	<body>
		<div id="app" v-cloak>
			<div class="list-view" ref="scrollBox" @scroll="handleScroll">
				<div class="list-view-phantom" :style="{
                       height: contentHeight
                    }"></div>
				<div ref="content" class="list-view-content">
					<div class="list-view-item" :style="{
                        height: itemHeight + 'px'
                      }" v-for="(item,index) in visibleData">
						{{item }}
					</div>
				</div>
			</div>
		</div>
		<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
		<script>
			new Vue({
				el: "#app",
				computed: {
					contentHeight() {
						return this.data.length * this.itemHeight + "px";
					},
				},
				mounted() {
					this.updateVisibleData();
				},
				data() {
					return {
						data:[],// new Array(1000).fill(1),
						itemHeight: 30,
						visibleData: [],
					};
				},
				created() {
					new Promise((resolve) => {
						let res = {
							total: 100000
						};
						let item = {
							stationDistance: 111,
							dataTime: "2022-06-15 07:07:07",
							stationDirection: 1,
						};

						res.data = [];
						for (let i = 0; i < res.total; i++) {
							res.data.push(item);
						}
						resolve(res);
					}).then(res => {
						this.data = res.data;
					})

				},
				methods: {
					updateVisibleData(scrollTop = 0) {
						const visibleCount = Math.ceil(
							this.$refs.scrollBox.clientHeight / this.itemHeight
						);
						const start = Math.floor(scrollTop / this.itemHeight);
						const end = start + visibleCount;
						this.visibleData = this.data.slice(start, end);
						this.$refs.content.style.webkitTransform = `translate3d(0, ${
              start * this.itemHeight
            }px, 0)`;
					},
					handleScroll() {
						const scrollTop = this.$refs.scrollBox.scrollTop;
						this.updateVisibleData(scrollTop);
					},
				},
			});
		</script>
	</body>
</html>
